package outPut

import (
	"fmt"
	"github.com/fatih/color"
	"github.com/gosuri/uitable"
	"db2s/global"
	"sync"
	"sync/atomic"
)

type (
	Rows struct {
		RowsSum      *int64 `json:"rowsSum"`
		SourceNumber *int64 `json:"srcCount"`
		DestNumber   *int64 `json:"dstCount"`
		InsertSum    *int64 `json:"insertSum"`
		UpdateSum    *int64 `json:"updateSum"`
		DeleteSum    *int64 `json:"DeleteSum"`
	}
	Sync struct {
		SyncSum    *int64 `json:"syncRows"`   //表的实际行数
		SelectRows *int64 `json:"selectRows"` //源端查询装填
		InsertRows *int64 `json:"insertRows"` //目标端写入状态
	}
	Struct struct {
		Role        string `json:"role"`
		IssueType   string `json:"issue Type"`
		DataFixType string `json:"fix Type"`
		ExecObject  string `json:"execObject"`
		ExecResult  string `json:"execStat"`
	}
	Object struct {
		Role        string `json:"role"`
		IssueType   string `json:"issue Type"`
		DataFixType string `json:"fix Type"`
		ExecObject  string `json:"execObject"`
		ExecResult  string `json:"execStat"`
	}
	Task struct {
		Sum            *int64 `json:"Sum"` //表的实际行数
		LobCN          string
		VarcharCN      string
		TextCN         string
		TextCT         string
		PType          string
		PSum           int64
		Histogram      string  `json:"histogram"` //源端查询装填
		RateEvaluation string  `json:"rate"`
		DataSize       float64 `json:"dataSize(MB)"`
	}
	HotSql struct {
		SourceNumber *int64 `json:"srcCount"`
		DestNumber   *int64 `json:"dstCount"`
		QpsSum       *int64 `json:"qps Sum"`
		SelectNum    *int64 `json:"select Num"`
		InsertNum    *int64 `json:"insert Num"`
		UpdateNum    *int64 `json:"update Num"`
		DeleteNum    *int64 `json:"delete Num"`
	}
	Load struct {
		SyncSum    *int64 `json:"syncSum"`    //表的实际行数
		SelectRows *int64 `json:"selectRows"` //源端查询装填
		InsertRows *int64 `json:"insertRows"` //目标端写入状态
	}
	TPod struct {
		Seq             int    `json:"seq"` //task打印的任务序号
		Schema          string `json:"schema"`
		Table           string `json:"table"`
		CheckMode       string `json:"mode"`
		Options         string `json:"options"`
		Role            string `json:"role"`
		IndexName       string `json:"indexName"`
		CardinalityRate string
		IndexType       string `json:"indexType"`
		IndexCol        string `json:"indexCol"`
		Rows            Rows   `json:"rows"`
		Sync            Sync   `json:"sync"`
		Struct          Struct `json:"struct"`
		Object          Object `json:"object"`
		Task            Task   `json:"task"`
		HotSql          HotSql `json:"hotSql"`
		Load            Load   `json:"load"`
		Result          string `json:"result"`
		TableMiss       bool
		Status          *int64 //表状态
	}
)
type Terminal struct {
	Pods chan any
	Sum  atomic.Value `json:"sum"`
	Mode string       `json:"mode"`
	Wg   *sync.WaitGroup
	//PrintFunc     global.EFunc
	ModifyValFunc                                     global.EFunc
	ExecFunc                                          []global.EFunc
	IgnoreSum                                         int64  `json:"ignoreSum"`
	BreakPointSum                                     int64  `json:"breakPointSum"`
	ExecTime                                          string `json:"execTime"`
	res                                               []any
	abnormalCount, normalCount, missCount, errorCount int64
}
type printResult struct {
	table         *uitable.Table
	podsSum       atomic.Value
	ignoreSum     int64
	breakPointSum int64
	execTime      string
	normalCount   int64
	abnormalCount int64
	missCount     int64
	errorCount    int64
}

func resultPrint(res printResult) {
	fmt.Println(res.table)
	fmt.Println()
	fmt.Println("----------------**********----------------")
	fmt.Println(fmt.Sprintf("db2s report: totalTime: %s (Seconds) checkTables: %s ignoreTableSum:%v breakPointTableSum:%v normalTabls: %s abnormalTables: %s errorTables:%s missTables: %s ", color.GreenString(res.execTime), color.YellowString(fmt.Sprintf("%v", res.podsSum.Load())), color.GreenString(fmt.Sprintf("%v", res.ignoreSum)), color.RedString(fmt.Sprintf("%v", res.breakPointSum)), color.GreenString(fmt.Sprintf("%v", res.normalCount)), color.RedString(fmt.Sprintf("%v", res.abnormalCount)), color.RedString(fmt.Sprintf("%v", res.errorCount)), color.RedString(fmt.Sprintf("%v", res.missCount))))
}

func NewTerminal(new Terminal) *Terminal {
	return &new
}
func (t *Terminal) Init(total int, pods chan any) {
	t.Pods = pods
	t.res = make([]any, total)
}
func (t *Terminal) Start() {
	t.Init(global.ChannelDefault, t.Pods)
}
func (t *Terminal) Stop() {
	close(t.Pods)
}
func (t *Terminal) AddFunc(f global.EFunc) {
	t.ExecFunc = append(t.ExecFunc, f)
}
func (t *Terminal) Write(pod any) {
	t.Pods <- pod
}
func (t *Terminal) Load(pods string, value any) (err error) {
	return dynamicModifyValue(t, pods, value)
}

func podCor(pod any) (pod1 *TPod) {
	switch pod.(type) {
	case *TPod:
		pod1 = pod.(*TPod)
	case TPod:
		pod2 := pod.(TPod)
		pod1 = &pod2
	}
	return
}
func (t *Terminal) count(pod any) (podRes TPod) {
	pod1 := podCor(pod)
	switch pod1.Result {
	case "miss":
		pod1.Result = "miss"
		t.missCount++
	case "abnormal":
		pod1.Result = "abnormal"
		t.abnormalCount++
	case "error":
		pod1.Result = "error"
		t.errorCount++
	default:
		t.normalCount++
	}
	podRes = *pod1
	return
}
func (t *Terminal) Print() {
	table := uitable.New()
	table.MaxColWidth = 200
	table.RightAlign(20)
	table.AddRow(RecursiveStructJsonName(t.Mode, TPod{})...)
	for _, pod := range t.res {
		if pod == nil {
			continue
		}
		table.AddRow(RecursiveStructJsonValue(t.Mode, t.count(pod))...)
	}
	resultPrint(printResult{
		table:         table,
		podsSum:       t.Sum,
		ignoreSum:     t.IgnoreSum,
		breakPointSum: t.BreakPointSum,
		execTime:      t.ExecTime,
		normalCount:   t.normalCount,
		abnormalCount: t.abnormalCount,
		missCount:     t.missCount,
		errorCount:    t.errorCount,
	})
	return
}
func (t *Terminal) Run() {
	t.Wg.Add(1)
	var qq int
	go func() {
		defer func() {
			t.Wg.Done()
		}()
		for {
			select {
			case c, d := <-t.Pods:
				if !d {
					return
				}
				qq++
				var e any
				if c != nil {
					e = t.ModifyValFunc.FuncName("", c)
					switch e.(type) {
					case TPod:
						t.res[e.(TPod).Seq-1] = c
					case *TPod:
						t.res[e.(*TPod).Seq-1] = c
					}
				}
				for _, v := range t.ExecFunc {
					if v.FuncName != nil {
						v.FuncName("", e)
					}
				}
			}
		}
	}()
}
